home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-03 / dosbasic.zip / ASM.ZIP / P1.ASM < prev    next >
Assembly Source File  |  1990-12-19  |  29KB  |  712 lines

  1. ;«RM82»«TS8,16,24,32,40,48,56»
  2. ;Updated 12/13/90
  3.  
  4. ;============================================================================
  5. ;   Copyright (C) Copr. 1990 by Sidney J. Kelly
  6. ;           All Rights Reserved.
  7. ;           Sidney J. Kelly
  8. ;           150 Woodhaven Drive
  9. ;           Pittsburgh, PA 15228
  10. ;           home phone 412-561-0950 (7pm to 9:30pm EST)
  11. ;============================================================================
  12.  
  13. DOSSEG
  14. .model medium
  15. .code
  16.  
  17. public PRINTRDY, CHECK87, FREERAM, EQUIPMENT, OTHERMEMORY, FINDDRIVES, ANSICHECK, ACTUALEXTND
  18.  
  19. ; Please do not remove
  20. Copyright       DB    13,10,'Copyright Copr. (C) 1990 Sidney J. Kelly',13,10
  21. Copyright1      DB    'All Rights Reserved',13,10,26
  22.  
  23. ;==========================================================================
  24. ;DECLARE FUNCTION PRINTRDY%(Lpt%)
  25. ; Input:
  26. ;       Lpt% gives portnumber to test
  27. ;       Lpt%=1 for LPT1:, 2 for LPT2:, etc
  28. ;
  29. ; Returns:
  30. ;        0 if not ready
  31. ;       -1 (True) if ready
  32. ;===========================================================================
  33.  
  34. EVEN
  35. PRINTRDY        PROC    FAR             ; Check LPT(Lpt%):
  36.     Push    BP
  37.     Mov     BP,SP
  38.     Mov     BX,[BP+6]
  39.     Mov     DX,[BX]
  40.     Dec     DX                      ; 0 biased
  41.     Cmp     DX,4                    ; make sure Lpt# is 0 to 3
  42.     JB      @f                      ;
  43.     Xor     AX,AX                   ; report out of range error
  44.     Jmp     Short  EXIT_1
  45. @@:
  46.     Mov     AH, 2                   ; Check printer status for
  47.     Int     17h                     ; Printer bios interrupt
  48.     Mov     DX, AX                  ; Put result in DX &
  49.     Xor     AX, AX                  ; assume no printer
  50.     TEST    DH, 00101001b           ; Are any error bits on?
  51.     JNE     EXIT_1                  ; Yes?  Error so exit
  52.     TEST    DH, 10010000b           ; Are both operation bits on?
  53.     JZ      EXIT_1                  ; No?  Error so exit
  54.     Mov     AX,-1                   ; Printer on line, returns -1
  55. EXIT_1:                                 ; Error or offline, returns 0
  56.     Pop     BP
  57.     Ret     2                       ; quits program & clears parameter
  58. PRINTRDY        Endp
  59.  
  60. ;=======================================================================
  61. ;DECLARE FUNCTION CHECK87%()
  62. ;Returns:
  63. ;        0 if no 80x87, or system equipment word not set.
  64. ;       87 if an 8087
  65. ;      -87 if 8087 emulation in use on an 80286 or 80386.  Because the
  66. ;           the 80287 has almost exactly the same instruction set as the
  67. ;           8087 few have felt a need to emulate the 80287.  I have not
  68. ;           seen an 80387 emulator in software.  The 80827 just includes
  69. ;           one new instruction (protected mode), nothing for use in
  70. ;           real mode.  80387 has transendental math routines.*
  71. ;
  72. ;      287 if an 80827
  73. ;      387 if an 80387 or 80487
  74. ; More accurate than checking the equipment word.   QBX, Version 7
  75. ; merely checks the equipment word to determine if an 80x87 is installed.
  76. ; I guess that can be used as a software toggle.
  77. ;
  78. ; * Intel recently released an 80287 that has 80387 transendental math
  79. ;   routines in it.  If someone sends me a new chip, I will write code
  80. ;   to test for it.
  81. ;
  82. ; Because of complaints about the traditional test with inexpensive clones
  83. ; (See Jon Waterhouse letter in Byte, Nov. 1990, page 40)
  84. ; routine first tests the equipment word in RAM bios.
  85. ;=======================================================================
  86. ;
  87. ;   REFERENCES:
  88. ;       basic info is adopted from Ted Forgeron's article in PC
  89. ;         Tech Journal, Aug '87 p43.
  90. ;       Copr. 1987      Pat Shea - Psi! (that Copr. is on there cuz my
  91. ;                                        lawyer sez I should, but feel
  92. ;                                        free to hack away!!!    pats.)
  93. ;     In the event of subsequent republication of this function,
  94. ;       please carry forward reference to these two gentlemen as
  95. ;       original authors.
  96. ;
  97. ; Minor beautification, addition of MASM 5.1 simplified
  98. ;    directives, detection of emulation, additional commentary by SJK 12/12/90
  99. ;
  100. ; The CX loop idea for slow PC's with a math chip is from the public
  101. ; domain INFOPLUS Version 1.35, Andrew Rossman 10/7/90
  102. ;=======================================================================
  103.  
  104. EVEN
  105. CTRL_Word dw     0              ; CTRL_Word word needed for the NDP test.
  106.                 ; In OS/2 probably will have to make
  107.                 ; this a local variable on the stack
  108.                 ; because cannot write to CSegment in
  109.                 ; OS/2.
  110. EVEN
  111. CHECK87   PROC FAR
  112.     Pushf                            ; save flags
  113.  
  114.     ; in response to clone errors, test to see if system knows
  115.     ; if math chip is installed. If Int 11h sez no, then
  116.     ; report no mathchip.  Can't check AT CMOS mathchip bit
  117.     ; because some clones do not set the bit in the CMOS, but
  118.     ; only set the bit in the Int 11h equipment word. E.g. ACER 910
  119.  
  120.     Int     11h
  121.     Test    AL,10b                   ; is mathchip bit Set?
  122.     JZ      No_Math_Chip             ; no mathchip
  123.  
  124.     ;Test for any mathchip
  125.     Mov     Word Ptr CTRL_Word,0h    ; clear CTRL_Word
  126.  
  127.     CLI    ; prevent interrupts so routine will work on slow PC's
  128. ; The next two 80x87 instructions cannot carry the WAIT prefix,
  129. ; because there may not be an 80x87 for which to wait.  The WAIT is
  130. ; therefore emulated with a MOV CX,<value>! LOOP $ combination.  This
  131. ; allow use of routine on an old PC with an 8087.
  132.  
  133.     Fninit                           ; try to initialize the NDP
  134.     ; use the no-wait state version of the op code so will not
  135.     ; hang a machine without a NDP.  Loop allows test of a PC that
  136.     ; does have an 8087.
  137.  
  138.     Mov     CX,2             ; a time waste loop
  139.         Loop    $                        ; allow 8087 time to react
  140.     
  141.     Fnstcw  CTRL_Word                ; put CTRL_Word in memory
  142.     ; use the no-wait state version of the op code so will not
  143.     ; hang a machine without a NDP.  Loop allows test of a PC that
  144.     ; does have an 8087.
  145.     Mov     CX,14h
  146.         Loop    $
  147.  
  148.     STI                 ; allow interrupts again
  149.     Cmp     byte ptr CTRL_Word+1, 3  ; if high byte = 3h then NDP found
  150.     Je      chk_87                   ; found something, so keep going
  151.  
  152. No_Math_Chip:
  153.     Xor     AX,AX                    ; else zero AX to show
  154.     Jmp     SHORT CHK_87_END         ;   no NDP
  155.  
  156. ;Test for 8087
  157. chk_87:
  158.     And     CTRL_Word,NOT 0080h      ; turn ON interrupts (IEM = 0)
  159.     Fldcw   CTRL_Word                ; load CTRL_Word word
  160.     Fdisi                            ; turn OFF interrupts (IEM = 1)
  161.     Fstcw  CTRL_Word                 ; store CTRL_Word word
  162.     Test   CTRL_Word,0080h           ; if IEM=1, 8087 (only 8087 pays
  163.                      ; attention to IEM)
  164.     Jz     Chk_287                   ; not an 8087, test for 80287
  165.  
  166. ;-------------------------------------------------------------------------
  167. ; Test for 8087 emulation by software.  Emulation only can be done on an
  168. ; 80286 or 80386.   So test for an 80286 or 80386 using quirk with flags
  169. ; I haven't seen a routine that emulates the 80287 so this is not tested
  170. ; for.  I am sure one exists though.  Emulation of an 8087/808287 is possible
  171. ; because of a special bit on the 80287 machine status register.  Exactly how 
  172. ; this emulation is done is light years beyond me.
  173. ; The only reason for testing for emulation is suggest to user that he
  174. ; would get faster results if he relied on MS QuickBasic built in 
  175. ; software emulation rather than other forms of software emulation.
  176. ;-------------------------------------------------------------------------
  177.     Xor    AX,AX                     ; clear AX
  178.     Push   AX                        ; put on stack
  179.     Popf                             ; put in flags
  180.     Pushf                            ; put back on stack
  181.     Pop    AX                        ; get flags back in AX
  182.     And    AX,0F000h                 ; clear all but upper 4 bits
  183.     Cmp    AX,0F000h                 ; if bits 12-15 are set then CPU
  184.     JE     @f                        ; is not an 80286, 80386 or 80486
  185.     Mov    AX,-87                    ; put -87 in AX to show that
  186.     Jmp    SHORT CHK_87_END          ;  emulation is detected
  187. @@:
  188.                      ; CPU is a NEC, 8086/88 or 80186/88
  189.     Mov    AX,87                     ; put 87 in AX to show
  190.     Jmp    SHORT CHK_87_END          ; found an 8087
  191.  
  192. ;Test for 80287
  193. Chk_287:
  194.     Finit                            ; set default infinity mode
  195.     Fld1                             ; push 1 on stack
  196.     Fldz                             ; push 0 on stack
  197.     Fdiv                             ; then divide. Make infinity
  198.                      ; by dividing 1 by zero
  199.     Fld    St                        ; push back on stack.   Change
  200.     Fchs                             ; sign & make negative infinity
  201.     Fcompp                           ; compare the two infinities
  202.  
  203.  ; Default after FINIT for 80287 & 8087 is projective infinity where
  204.  ; both positive and negative infinity are equal.  80387 & 80486 use
  205.  ; affine infinity, and ignore projective infinity.  Under affine
  206.  ; infinity positive and negative infinity are at opposite ends of the
  207.  ; number line and are not equal.  (SJK Who thinks of these things???)
  208.  
  209.     Fstsw  CTRL_Word                 ; store status for result
  210.     Fwait                            ; wait until status word is stored
  211.     Mov    AX,CTRL_Word              ; get CTRL_Word word
  212.     Sahf                             ; put highbyte (AH) into flags
  213.     Jnz    Got_387                   ; If bit 6 (infinity control)
  214.                      ; not set then it is a 80387
  215.     Mov    AX,287                    ; report that it is an 80287
  216.                      ; since we tested for an 8087
  217.     Jmp    SHORT CHK_87_END
  218.  
  219. ; NDP  not an 8087 or an 80287 so it must be an 80387.  The 80387 ignores
  220. ; the infinity control (IC) flag, 80287/8087 does not. SJK
  221.  
  222. Got_387:
  223.     Mov    AX,387                   ; return 387
  224. CHK_87_END:
  225.     Popf                            ; restore flags
  226.     ret                             ; end, return to main routine
  227. CHECK87       ENDP
  228.  
  229. ;===========================================================================
  230. ; DECLARE SUB EQUIPMENT(ConvMem%,PrinterPorts%,ComPorts%)
  231. ; Returns amount of Conventional Memory in KB
  232. ;       number of Parallel Ports
  233. ;         number of COM ports
  234. ;===========================================================================
  235.  
  236. ConvMem         EQU     [BP+10]
  237. PrinterPorts    EQU     [BP+8]
  238. ComPorts        EQU     [BP+6]
  239.  
  240. EVEN
  241. EQUIPMENT       PROC    FAR
  242.     Push    BP              ; save stack frame
  243.     Mov     BP,SP           ; address stack
  244.     Int     12h             ; get conventional memory
  245.     Mov     BX,ConvMem      ; point to ConvMem%
  246.     Mov     [BX],AX         ; Place value in ConvMem%
  247.     Xor     DX,DX           ; clear DX for use
  248.     Int     11h             ; Call get equipment interrupt
  249.     Mov     AL,AH           ; just look at top 8 bits
  250.                 ; save them in AH
  251.                 ; use AL to manipulate
  252.     Mov     CL,06           ; Dump bits 8-13,
  253.     SHR     AL,CL           ; and move 14 & 15 to lower positions
  254.     And     AL,03           ; mask any other positions
  255.     Mov     DL,AL           ; Move Printers%
  256.     Mov     BX,PrinterPorts ; Point to PrinterPorts%
  257.     Mov     [BX],DX         ; And store in PrinterPorts%
  258.     Mov     AL,AH           ; Get top 8 bits again
  259.     SHR     AL,1            ; This time look at bits 9, 10 & 11
  260.     And     AL,07           ; by masking for 3 bits
  261.     Mov     DL,AL           ; And move ComPorts to DL
  262.     Mov     BX,ComPorts     ; Point to ComPorts%
  263.     Mov     [BX],DX         ; And store in ComPorts%
  264.     Pop     BP              ; restore BP
  265.     Ret     6               ; remove 2*3 parameters
  266. EQUIPMENT       Endp
  267.  
  268. ;======================================================================
  269. ; DECLARE SUB OTHERMEMORY(EXTENDED%,EXPANDED%,XMS%)
  270. ; Returns size of extended, expanded, and XMS memory.
  271. ; Extended = only size that BIOS reports is free
  272. ; Expanded = total installed.
  273. ; XMS      = total installed.
  274. ;
  275. ; Uses the rom ID byte approach to determine if extended memory supported.
  276. ;======================================================================
  277.  
  278. .code
  279.     EXPMEM            DB      "EMMXXXX0"
  280.     EXPMEM_LENGTH     EQU     $-EXPMEM
  281.     EVEN
  282.     Drv_ADDR          DD      0     ; This will hold address of
  283.                     ; HIMEM.SYS driver
  284.  
  285. EVEN
  286. OTHERMEMORY    PROC     FAR
  287.     Push    BP
  288.     Mov     BP,SP                   ; save all registers used
  289.     Push    DI
  290.     Push    SI
  291.  
  292. ;---------------------------------------------------------------------------
  293. ; Find Extended Memory Size
  294. ;---------------------------------------------------------------------------
  295.  
  296.     Xor     BX,BX                   ; assume no extended memory
  297.     Mov     AX,0FFFFh               ; Read system byte
  298.     Mov     ES,AX                   ; Store segment in ES
  299.     Mov     AL,ES:[0EH]             ; Get System ID.
  300.     Cmp     AL,0FCh                 ; Check if AT, PS/2 Model 50 & 60
  301.                     ; most AT clones use same code too
  302.                     ; including COMPAQ 286 & 386 machines
  303.                     ; PS/2 Model 30/286, AT&T 6300 Plus
  304.                     ; Tandy AT clones, etc.
  305.     JZ      Find_Extended           ; If AT, get extended.
  306.     Cmp     AL,0F8h                 ; Check if &HF8: Model 80 & Model 70
  307.                     ; or Model 55SX
  308.     JZ      Find_Extended           ; OK, get extended.
  309.     Jmp     Short  Exnted_Exit      ; else exit, because PC, XT, JR,
  310.                     ; Convertible, Model 25, 30, other.
  311. Find_Extended:
  312.     Mov     AH,88h                  ; Retrieve extended memory size.
  313.     CLC                             ; a fix for IBMCACHE
  314.                     ; documented in P.C. Mag
  315.                     ; June 27, 1989, page 303 EMS40.SYS
  316.                     ; same fix in XMS.SYS version 2.03
  317.     Int     15h                     ; value returned in AX
  318.     JC      Exnted_Exit             ; If carry set, then error.
  319.                     ; This should stop errors in clones
  320.                     ; too.
  321.     Mov     BX,AX                   ; o.k., store value in BX temporarily
  322.  
  323. Exnted_Exit:
  324.     STI                             ; I think this will prevent crash on
  325.                     ; AT&T 6300 (though an AT&T 6300 would
  326.                     ; not get this far). AT&T bios error 
  327.                     ; is  the failure to reset interrupts??
  328.                     ; This should not be a problem with
  329.                     ; AT&T 6300 Plus and later models
  330.                     ; after calling Int 15h
  331.     Mov     AX,BX                   ; get value from BX & store in AX
  332.     Mov     BX,[BP+10]
  333.     Mov     [BX],AX                 ; store back in integer variable
  334.  
  335. ;---------------------------------------------------------------------------
  336. ;Find Expanded Memory Size
  337. ;---------------------------------------------------------------------------
  338.  
  339.     Mov     AX,3567h                ; Retrieve EMM interrupt vector.
  340.     Int     21h                     ; stores result in ES:BX
  341.     Xor     BX,BX                   ; Assume no expanded memory.
  342.     Mov     DI,0Ah                  ; Set DI to offset 10 of vector
  343.     Cld                             ; clear the direction flag
  344.     Push    DS                      ; Save DS
  345.     Mov     AX,CS
  346.     Mov     DS,AX                   ; Set DS to CS
  347.  
  348.     Assume  DS:@code
  349.  
  350.     Mov     SI,OFFSET CS:EXPMEM     ; DS:SI points to EMMXXXX0.
  351.     Mov     CX,EXPMEM_LENGTH        ; CX has length of "EMMXXXX0"
  352.     REPZ    CMPSB                   ; ES:DI destination, DS:SI source
  353.     Pop     DS                      ; restore DS
  354.  
  355.     Assume  DS:@data
  356.  
  357.     JNZ     EXPANDED_EXIT           ; If no, then no LIM manager.
  358.     Mov     AH,42h                  ; Else, retrieve free expanded.
  359.     Int     67h                     ; returns free pages in BX
  360.                     ; total pages in DX
  361.     Xor     BX,BX                   ; clear BX to catch errors
  362.     Or      AH,AH                   ; if AH = 0 then EMS is ok
  363.     JZ      @f                      ; so jump forward, else
  364.     Mov     BX,-1                   ; report EMS with error
  365.     Jmp     Short EXPANDED_EXIT     ; EMS error so exit
  366. @@:
  367.     Mov     AX,16                   ; multiply total page count by 16
  368.     Mul     DX                      ; this converts DX pages to KB
  369.                     ; result in DX:AX
  370.     Mov     BX,AX                   ; store AX in BX temporarily
  371.  
  372. EXPANDED_EXIT:
  373.     Mov     AX,BX                   ; get value from BX & store in AX
  374.     Mov     BX,[BP+8]
  375.     Mov     [BX],AX
  376.  
  377. ;---------------------------------------------------------------------------
  378. ; XMS Memory test
  379. ; Source:  XMS Specs  (Microsoft 1989)
  380. ; Note unless you have version 2.06 or higher, information is not accurate
  381. ; i.e. 64kb of HIMEM area is reported as free when that is not so.
  382. ; This routine will adjust free XMS if version <2.06  and >1.xx.  The only 
  383. ; common version with this error is Version 2.04.
  384. ;---------------------------------------------------------------------------
  385.     Mov     AH,30h                  ; test DOS version
  386.     Int     21h                     ; if less than 3.x XMS does
  387.     Cmp     AL,3                    ; not exist
  388.     JB      XMS_err                 ; so quit now
  389.     Mov     AX,4300h                ; call Int 2Fh function.  Int 2Fh
  390.     Int     2Fh                     ; wasn't initialized before DOS 3.xx
  391.     Cmp     AL,80h
  392.     Je      XMS1                    ; XMS exists so jump forward
  393. XMS_err:
  394.     Mov     AX,0                    ; XMS does not exist or error
  395.     Jmp     Short XMS_end           ; so exit
  396. XMS1:
  397.     Mov     AX,4310h                ; get address of XMS driver
  398.     Int     2Fh                     ; from ES:BX
  399.     Mov     Word Ptr Drv_ADDR,BX    ; save far pointer
  400.     Mov     Word Ptr Drv_ADDR+2, ES ; from XMS for use below
  401.     Xor     AH,AH                   ; call function 0
  402.     Call    [Drv_ADDR]              ; indirect far call to driver
  403.     Cmp     AX,0200h                ; if not version 2 or above
  404.     Jb      XMS_err                 ; then quit, too old to be useful
  405.     Xor    DI,DI            ; Assume minor version is 2.06 or 
  406.                     ; above
  407.     Cmp    BX,0206h        ; check minor version (BCD number)
  408.         Jae    FindFree            ; verion o.k., so we will skip ahead
  409.  
  410. ;---------------------------------------------------------------------------
  411. ; Minor versions before Version 2.06 incorrectly reported HMA as part of free
  412. ; XMS space, SO LONG AS none of the XMS had been allocated.  As soon as any
  413. ; space was allocated the amount of purported free space was corrected.
  414. ; Version 2.06 corrected this bug.  Most recent version of HIMEM.SYS is
  415. ; Version 2.60, July 1990.  Existence of error observed with Version 2.04,
  416. ; (10/6/88), the version that came with Windows 286.
  417. ;---------------------------------------------------------------------------
  418.  
  419.     Mov    DI,64            ; remember to eliminate 64kb from
  420.                     ; amount reported as free
  421. FindFree:
  422.     Mov     AH,08
  423.     Call    [Drv_ADDR]              ; indirect far call to driver
  424.     Or      AX,AX                   ; if AX <> 0
  425.     JNZ     XMS2                    ; then no error occured
  426.     Cmp     BL,0A0h                 ; if BL set (all XMS allocated)
  427.     JZ      XMS2                    ; then no error,
  428.  
  429. BadNum:
  430.     Mov     DX,-1                   ; else report XMS error
  431.                     ; for all other error codes
  432.     Jmp    Short    PropVer
  433.  
  434. XMS2:
  435.     Or    DI,DI            ; was version less than 2.06?
  436.     JZ    PropVer            ; nope, so skip ahead
  437.     Mov    CX,DX            ; store DX in CX
  438.                     ; CMOS routine destroys AX,DX
  439.  
  440. ;------------------------------------------------------------------------------
  441. ; Solution to problem is to compare amount of Extended Memory installed
  442. ; with amount of XMS free.  If number is the same, the HIMEM area is
  443. ; erronously included in XMS free number and we have to reduce XMS free
  444. ; by 64 kb in verions before 2.06.
  445. ;------------------------------------------------------------------------------
  446.  
  447.     Mov     AL,48                   ; tell CMOS want to look at
  448.     Out     70h,AL                  ; byte in register 48
  449.     In      AL,71h                  ; the low byte of extended memory
  450.     Mov     BL,AL                   ; store in BL
  451.     Mov     AL,49                   ; tell CMOS want to look at
  452.     Out     70h,AL                  ; byte in register 49
  453.     In      AL,71h                  ; the high byte of extended memory
  454.     Mov     BH,AL                   ; store in BH
  455.     Mov    DX,CX            ; get XMS free value back again
  456.     Cmp     DX,BX                   ; total free = total installed?
  457.                     ; if no, then some space has been 
  458.                     ; allocated in XMS so do not have to
  459.                     ; make a correction.
  460.     JNE    PropVer            ; no, so skip ahead as no adjustment
  461.                     ; is necessary
  462.     Sub     DX,DI                   ; else reduce free mem. by HMA space
  463.  
  464. PropVer:
  465.     Mov     AX,DX                   ; store free memory in AX
  466.                     ; KB of free extended in AX
  467. XMS_end:
  468.     Mov     BX,[BP+6]               ; get address of last parameter
  469.     Mov     [BX],AX                 ; store AX in XMS%
  470.  
  471. ;Final Cleanup
  472.  
  473.     Pop     SI                      ; restore all the registers we used
  474.     Pop     DI
  475.     Pop     BP
  476.     Ret     6                       ; 2 * 3 parameters
  477. OTHERMEMORY Endp
  478.  
  479. ;===========================================================================
  480. ; DECLARE FUNCTION FINDDRIVES% ()
  481. ; Returns number of current logical drives w/o any errors
  482. ;
  483. ; Because LASTDRIVE default value = 5, it is likely that
  484. ; number of logical drives will be less than LASTDRIVE in CONFIG.SYS
  485. ; This routine will miss a drive if there are gaps between logical drives
  486. ; as can occur if SUBST is used.
  487. ;===========================================================================
  488.  
  489. .code
  490. EVEN
  491. Storage  DB      0
  492.  
  493. EVEN
  494. FINDDRIVES PROC  FAR
  495.      Push     BP
  496.      Mov      BP,SP
  497.      Mov      AH,19h          ; read default drive
  498.      Int      21h
  499.      Mov      CS:Storage,AL   ; store default in Storage
  500.      Mov      AH,30h          ; read DOS version
  501.      Int      21h
  502.      Cmp      AL,02           ; if less than 3.xx then exit
  503.      JBE      Dos_Ver2        ; because DOS ver <3.xx returns total number
  504.                   ; of logical drives in AL so we don't
  505.                   ; need to test.
  506.      Mov      DL,CS:Storage   ; put default back in DL
  507.  
  508. Main_Loop:
  509.      Mov      AH,0Eh          ; select default drive
  510.      Inc      DL              ; add one to the current default
  511.      Int      21h             ; read next drive above current
  512.      Mov      AH,19h          ; read default drive
  513.      Int      21h
  514.      Cmp      AL,DL           ; did default change?
  515.      JZ       Main_Loop       ; yes so jump back
  516.      Push     DX              ; save next drive
  517.      Mov      DL,CS:Storage   ; reload current
  518.      Mov      AH,0Eh          ; select orginal drive
  519.      Int      21h
  520.      Pop      DX              ; get next drive
  521.      Mov      AL,DL           ; store in AL
  522.      Jmp      Short Exit_Routine
  523.  
  524. Dos_Ver2:
  525.      Mov      DL,CS:Storage   ; reset current
  526.      Mov      AH,0Eh          ; In version 2, max logical drives in AL
  527.      Int      21h             ; in version 2, min number of drives is 2
  528.  
  529. Exit_Routine:
  530.      Xor      AH,AH           ; clear AH, since limit is 26 logical drives
  531.      Xor      DX,DX
  532.      Pop      BP
  533.      Ret                      ; exit
  534. FINDDRIVES Endp
  535.  
  536. ;============================================================================
  537. ; DECLARE FUNCTION ANSICHECK%()
  538. ;      IF ANSICHECK% THEN
  539. ;         PRINT "ANSI.SYS is installed."
  540. ;
  541. ; Source:  Disassembled COMMAND.COM Version 3.3 of CLS command
  542. ;        xxxx:2B62h is the beginning of the routine
  543. ;
  544. ;               VERY FAST and NOT MESSY!!!!
  545. ;
  546. ;This is the same method that COMMAND.COM uses to test for ANSI.SYS
  547. ;so every utility had better allow for this testing method.
  548. ;
  549. ; NOTE: PC Magazine's ANSI.COM even if turned off will still report ANSI.SYS
  550. ;       present, (it was planned that way so it would handle CLS).
  551. ;============================================================================
  552.  
  553. EVEN
  554. ANSICHECK PROC  FAR
  555.     Push    BP
  556.     Mov     CX,-1           ; assume that ANSI is installed
  557.     Mov     AX,3529h        ; get address of INT 29h (FAST PUTCHAR)
  558.     Int     21h
  559.     Mov     DX,ES           ; store segment in DX
  560.     Mov     AX,3520h        ; get address of INT 20h, terminate function
  561.     Int     21h             ; INT 20h usually points to COMMAND.COM
  562.     Mov     AX,ES
  563.     Cmp     DX,AX           ; if segment for INT 29 > INT 20 then ANSI
  564.     JA      Ender1          ; is installed
  565.     Xor     CX,CX           ; else, ANSI not installed
  566. Ender1:
  567.     Mov     AX,CX           ; store status in AX
  568.     Xor     DX,DX
  569.     Pop     BP
  570.     Ret
  571. ANSICHECK ENDP
  572.  
  573.     COMMENT        |
  574. The following routine is included just to show an alternative method.  To use
  575. remove the comment and add name to PUBLIC
  576. ;===========================================================================
  577. ; DECLARE FUNCTION OTHERANSI ()
  578. ; OTHERANSI
  579. ;
  580. ; RETURNS
  581. ;        0 if ANSI.SYS or ANSI.COM not installed
  582. ;       -1 if ANSI.SYS or ANSI.COM installed
  583. ;
  584. ; Theory:
  585. ;       Uses DOS CON driver to request ANSI cursor report.  If ANSI is
  586. ;       installed cursor report will store current cursor location in CON.
  587. ;       The curor report is a minimum of 6 bytes long, and it could
  588. ;       be longer.  Therefore, routine clears out CON driver.
  589. ;
  590. ;       Failure to clean out CON means DOS will read garbage as a file
  591. ;       load request at end of QBASIC program.  QBASIC never reads CON,
  592. ;       only reads the keyboard.  DOS reads CON when running COMMAND.COM.
  593. ;       This detection method is a reliable, though messy way, to do it
  594. ;       because it will overwrite display if ANSI is not installed.
  595. ;
  596. ; Caution:
  597. ; If ANSI is not loaded will overwrite display at current BIOS cursor
  598. ; location.  QBASIC routine should set cursor with LOCATE and overwrite
  599. ; area with text if ANSI not found.  DOS appears to write only to page 0
  600. ;===========================================================================
  601.  
  602. .code
  603.  
  604. EVEN
  605. CursReport  DB      27,'[6n$'          ; ANSI Report Cursor sequence
  606.  
  607. EVEN
  608. OTHERANSI PROC  FAR
  609.     Push    BP
  610.     Push    DS
  611.     Mov     AX,0C00h                ; clear keyboard buffer
  612.     Int     21h                     ; using a safe method
  613.                     ; there are faster methods
  614.     Mov     AX,CS
  615.     Mov     DS,AX                   ; make DS == CS
  616.  
  617.     Assume  DS:@code                ; DOS uses DS:DX to point to
  618.                     ; source of Output String
  619.  
  620.     Mov     DX, OFFSET CursReport   ; ANSI CMD to get cursor position
  621.     Mov     AH, 9                   ; Write ANSI escape sequence DS:DX
  622.     Int     21h                     ; to display with DOS String output
  623.  
  624.     Mov     AH, 6                   ; Read & ignore Esc character
  625.     Mov     DL, 0FFh                ; in keyboard buffer
  626.     Int     21h
  627.     JZ      ErrorExit               ; If ZF set, then ANSI not loaded
  628.     Mov     AH, 6                   ; Read & ignore "[" character
  629.     Int     21h
  630.     JZ      ErrorExit               ; If ZF set, then ANSI not loaded
  631.     Mov     AH, 6                   ; Get 1st digit of cursor row
  632.     Int     21h
  633.     JZ      ErrorExit               ; If ZF set, then ANSI not loaded
  634.  
  635.     Mov     BX, -1                  ; Return -1 if ANSI is installed
  636.     Jmp     SHORT Clear_CON_Loop
  637.  
  638. ErrorExit:
  639.     Sub     BX, BX                  ; Return 0 if ANSI
  640.                     ; driver not installed
  641. Clear_CON_Loop:
  642.     Mov     AH, 6                   ; clear out rest of control
  643.     Mov     DL, 0FFh                ; information from CON
  644.     Int     21h                     ; driver if ANSI is installed
  645.     JNZ     Clear_CON_Loop          ; and cursor not at LOCATE 1,1
  646.  
  647.     Mov     AX,BX                   ; restore value from BX in AX
  648.                     ; for return through function
  649.     Pop     DS                      ; restore DS
  650.  
  651.     Assume  DS:@data
  652.  
  653.     Pop     BP                      ; restore BP
  654.     Ret
  655. OTHERANSI ENDP
  656.     |
  657.  
  658.  
  659. ;============================================================================
  660. ; DECLARE FUNCTION ACTUALEXTND% ()
  661. ; Returns:
  662. ;       Actual amount of extended memory installed on 80286, 80386 or 80486
  663. ;       machine as stored in CMOS RAM
  664. ;       If clock battery is bad, will return a -1
  665. ;============================================================================
  666.  
  667. EVEN
  668. ACTUALEXTND PROC FAR
  669.     Xor     BX,BX                   ; assume no extended memory
  670.     Mov     AX,0FFFFh               ; Read system byte
  671.     Mov     ES,AX                   ; Store segment in ES
  672.     Mov     AL,ES:[0EH]             ; Get System ID.
  673.     Cmp     AL,0FCh                 ; Check if AT, PS/2 Model 50 & 60
  674.                     ; most AT clones use same code too
  675.                     ; including COMPAQ 286 & 386 machines
  676.                     ; PS/2 Model 30/286, AT&T 6300 Plus
  677.     JZ      Find_Extended1          ; If AT, get extended.
  678.     Cmp     AL,0F8h                 ; Check if &HF8: Model 80 & Model 70
  679.                     ; or Model 55SX
  680.     JZ      Find_Extended1          ; OK, get extended.
  681.     Jmp     Short  Finis2           ; else exit, because PC, XT, JR,
  682.                     ; Convertible, Model 25, 30, other.
  683.                     ; Can't just test for 80286 chip
  684.                     ; because could be on an accelerator
  685.                     ; board
  686. Find_Extended1:
  687.     Mov     AL,14                   ; see if battery good in
  688.     Out     70h,AL                  ; CMOS status register D
  689.     In      AL,71h
  690.     Test    AL,80h                  ; bit 7 set if battery bad
  691.     JNZ     Finis3                  ; if set quit
  692.  
  693.     Mov     AL,48                   ; tell CMOS want to look at
  694.     Out     70h,AL                  ; byte in register 48
  695.     In      AL,71h                  ; the low byte of extended memory
  696.     Mov     BL,AL                   ; store in BL
  697.  
  698.     Mov     AL,49                   ; tell CMOS want to look at
  699.     Out     70h,AL                  ; byte in register 49
  700.     In      AL,71h                  ; the high byte of extended memory
  701.     Mov     BH,AL                   ; store in BH
  702.  
  703. Finis2:
  704.     Mov     AX,BX                   ; put BX in AX to report size
  705.     Xor     DX,DX                   ; in case call as Long
  706.     Ret
  707. Finis3:
  708.     Mov     BX,-1                   ; put -1 in BX if clock battery bad
  709.     Jmp     Short   Finis2
  710. ACTUALEXTND ENDP
  711. END
  712.